<?php
/**
 * This file is part of the sfFilebasePlugin package.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @package   de.optimusprime.sfFilebasePlugin
 * @author    Johannes Heinen <johannes.heinen@gmail.com>
 * @license   MIT license
 * @copyright 2007-2009 Johannes Heinen <johannes.heinen@gmail.com>
 */

/**
 * @todo: remove me. this is a workaround for the problem that
 *        sfValidatedFile does not have its own class file.
 */
class ____dummy extends sfValidatorFile{};

/**
 * sfFilebasePluginUploadedFile represents a uploaded File and provides methods
 * to handle one.
 *
 * @see        sfFilebasePluginFile
 */
class sfFilebasePluginUploadedFile extends sfValidatedFile
{
  const
    UPLOAD_ERR_OK         = UPLOAD_ERR_OK,
    UPLOAD_ERR_INI_SIZE   = UPLOAD_ERR_INI_SIZE,
    UPLOAD_ERR_FORM_SIZE  = UPLOAD_ERR_FORM_SIZE,
    UPLOAD_ERR_PARTIAL    = UPLOAD_ERR_PARTIAL,
    UPLOAD_ERR_NO_FILE    = UPLOAD_ERR_NO_FILE,
    UPLOAD_ERR_CANT_WRITE = UPLOAD_ERR_CANT_WRITE,
    UPLOAD_ERR_EXTENSION  = UPLOAD_ERR_EXTENSION,
    UPLOAD_ERR_NO_TMP_DIR = UPLOAD_ERR_NO_TMP_DIR;
  
  /**
   * @var string
   */
  protected $error;
  
  /**
   * @var sfFilebasePluginUploadedFilesManager
   */
  protected $manager;

  /**
   * Constructor
   * 
   * @param string    $name
   * @param string    $tmp_name
   * @param string    $type
   * @param string    $error
   * @param string    $size
   * @param string    $path: The directory where the uploaded file will be saved.
   *                         Default is null. $path might be delegated through
   *                         a whole form validation process, where all
   *                         instances of sfFilebasePluginUploadedFiles be
   *                         generated by the validator and files moved by
   *                         the orm-form instance.
   * @param sfFilebasePluginUploadedFilesManager $manager:
   *                         The manager to access the appropriate filebase context
   *
   *
   */
  function __construct($originalName, $type, $tempName, $size, $path = null, $error = null, sfFilebasePluginUploadedFilesManager $manager)
  {
    parent::__construct($originalName, $type, $tempName, $size, $path);

    $this->manager = $manager;

    if (empty($error))
    {
      $this->error    = self::UPLOAD_ERR_OK;
    }
    else
    {
      $this->error = $error;
    }
    
    if (empty($size) || empty($type))
    {
      $tmp_file = $this->manager->getFilebase()->getFilebaseFile($tempName);
      if(empty($size))
      {
        $size = $tmp_file->getSize();
        $this->size = $size;
      }
      if(empty($type))
      {
        $type = $tmp_file->getMimeType('application/octet-stream');
        $this->type = $type;
      }
    }
  }

  /**
   * Returns the file extension, based on the content type of the file.
   *
   * @param  string $default  The default extension to return if none was given
   *
   * @return string The extension (with the dot)
   */
  public function getExtension($default = '')
  {
    $f = $this->manager->getFilebase()->getFilebaseFile($this->getTempName());
    return
      ($mime = sfFilebasePluginUtil::getMimeType($f, null, ltrim($this->getOriginalExtension(), '.'))) === null ?
      $default :
      '.' . sfFilebasePluginUtil::getExtensionByMime($mime, $default);
  }

  /**
   * Returns the original uploaded file name extension.
   *
   * @param  string $default  The default extension to return if none was given
   *
   * @return string The extension of the uploaded name (with the dot)
   */
  public function getOriginalExtension($default = '')
  {
    $f = $this->manager->getFilebase()->getFilebaseFile($this->getOriginalName());
    $ext = $f->getExtension();
    return $ext ? '.'.$ext : $default;
  }

  /**
   * Sets the path to the file where the uploaded data have to be stored.
   * @param string $path: absolute pathname to directory.
   */
  public function setPath($path)
  {
    $this->path = $path;
  }

  /**
   * Moves an uploaded file into its final destination.
   * Inclusion and exclusion rules consist of regex-strings,
   * they are used to check the target filenames against them.
   * Exclusion:   Matched filenames throw exceptions.
   * Inclusion:   Matched filenames will be passed as valid filenames.
   *
   * $destination can be a string (absolute or relative (to sfFilebasePlugin) pathname) or an
   * instance of sfFilebasePluginFile.
   *
   * @param mixed       sfFilebasePluginFile | string $destination_directory: Target directory to save the uploaded file
   * @param boolean     $overwrite: True if existing files should be overwritten
   * @param string      $file_name: If given, uploaded file will be renamed after moving.
   * @param array       $inclusion_rules: Rules defining files to be explicetly allowed
   * @param array       $exclusion_rules: Rules defining files to be not allowed
   */
  public function moveUploadedFile($destination_directory = null, $file_name = null, $overwrite = true, $chmod = null, array $inclusion_rules = array(), array $exclusion_rules = array())
  {
    $destination_directory = $destination_directory === null ? $this->getPath() : $destination_directory;
    try
    {
      $file = $this->manager->getFilebase()->moveUploadedFile($this, $destination_directory, $file_name, $overwrite, $chmod, $inclusion_rules, $exclusion_rules);
      if($file_name === null)
      {
        $this->savedName = $this->getOriginalName();
      }
      else
      {
        $this->savedName = $file_name;
      }
      return $file;
    }
    catch (Exception $e)
    {
      throw $e;
    }
  }

  /**
   * Saves the uploaded file.
   *
   * This method can throw exceptions if there is a problem when saving the file.
   *
   * If you don't pass a file name, it will be generated by the generateFilename method.
   * This will only work if you have passed a path when initializing this instance.
   *
   * @param  string $file      The file path to save the file
   * @param  int    $fileMode  The octal mode to use for the new file
   * @param  bool   $create    Indicates that we should make the directory before moving the file
   * @param  int    $dirMode   The octal mode to use when creating the directory
   *
   * @return string The filename without the $this->path prefix
   *
   * @throws Exception
   */
  public function save($file = null, $fileMode = null, $create = true, $dirMode = 0777)
  {
    if ($file === null)
    {
      if($this->originalName === null)
      {
        $file = $this->generateFilename();
      }
      else
      {
        $file = $this->originalName;
      }
    }

    $filebase = $this->manager->getFilebase();

    // copy the temp file to the destination file
    $file = $filebase->getFilebaseFile($this->getTempName())->copy($file, true);

    // chmod our file
    if($fileMode !== null)
      $file->chmod($fileMode);

    $this->savedName = $file->getPathname();

    return $file;
  }

  /**
   * Returns true if there are file upload errors.
   * If the argument $errcode is given, state is
   * checked by this specific errcode.
   * @example $file->isError()
   * @example $file->isError(sfFilebaseUploadedFile::UPLOAD_ERR_NO_FILE)
   * @return boolean
   */
  public function isError($errcode = null)
  {
    if($errcode === null || $errcode === self::UPLOAD_ERR_OK)
    {
      return $this->hasError();
    }
    return $this->getError() === $errcode;
  }

  public function hasError()
  {
    return $this->getError() !== self::UPLOAD_ERR_OK;
  }

  /**
   * Returns the error code of
   * the uploaded file
   * @return integer $error_code
   */
  public function getError()
  {
    return $this->error;
  }

  /**
   * Returns the upload file manager. This can be used
   * to access the current filebase context.
   * @return sfFilebasePluginUploadedFilesManager $manager
   */
  public function getManager()
  {
    return $this->manager;
  }
}